// +FHDR============================================================================/
// Author       : hjie
// Creat Time   : 2024/11/15 14:39:27
// File Name    : axi4_mdl.v
// Module Ver   : Vx.x
//
//
// All Rights Reserved
//
// ---------------------------------------------------------------------------------/
//
// Modification History:
// V1.0         initial
//
// -FHDR============================================================================/
// 
// axi4_mdl
//    |---
// 
`timescale 1ns/1ps

module axi4_mdl #
(
    parameter                           NDEV = 2                    ,
    parameter                           IDW = 4                     ,
    parameter                           DW = 32                     ,
    parameter                           DEW = DW/8                  ,
    parameter                           AW = 32                     ,
    parameter                           MAX_BURST_LEN = 64          ,
    parameter                           U_DLY = 1                     // 
)
(
// ---------------------------------------------------------------------------------
// CLock & Reset
// ---------------------------------------------------------------------------------
    input                    [NDEV-1:0] clk_axi                     , 
    input                               rst_n                       ,
// ---------------------------------------------------------------------------------
// User Data
// ---------------------------------------------------------------------------------
    input        [MAX_BURST_LEN*DW-1:0] axi_wrmem                   , 
// ---------------------------------------------------------------------------------
// AXI4
// ---------------------------------------------------------------------------------
    output reg           [NDEV*IDW-1:0] axi4_awid                   , 
    output reg            [NDEV*AW-1:0] axi4_awaddr                 , 
    output reg             [NDEV*8-1:0] axi4_awlen                  , 
    output reg             [NDEV*3-1:0] axi4_awsize                 , 
    output reg             [NDEV*2-1:0] axi4_awburst                , 
    output reg               [NDEV-1:0] axi4_awvalid                , 
    input                    [NDEV-1:0] axi4_awready                , 
                                             
    output reg            [NDEV*DW-1:0] axi4_wdata                  , 
    output reg           [NDEV*DEW-1:0] axi4_wstrb                  , 
    output reg               [NDEV-1:0] axi4_wlast                  , 
    output reg               [NDEV-1:0] axi4_wvalid                 , 
    input                    [NDEV-1:0] axi4_wready                 , 
                                             
    input                  [NDEV*2-1:0] axi4_bresp                  , 
    input                    [NDEV-1:0] axi4_bvalid                 , 
    output                   [NDEV-1:0] axi4_bready                 , 
                                           
    output reg           [NDEV*IDW-1:0] axi4_arid                   , 
    output reg            [NDEV*AW-1:0] axi4_araddr                 , 
    output reg             [NDEV*8-1:0] axi4_arlen                  , 
    output reg             [NDEV*3-1:0] axi4_arsize                 , 
    output reg             [NDEV*2-1:0] axi4_arburst                , 
    output reg               [NDEV-1:0] axi4_arvalid                , 
    input                    [NDEV-1:0] axi4_arready                , 
                                             
    input                 [NDEV*DW-1:0] axi4_rdata                  , 
    input                  [NDEV*2-1:0] axi4_rresp                  , 
    input                    [NDEV-1:0] axi4_rlast                  , 
    input                    [NDEV-1:0] axi4_rvalid                 , 
    output                   [NDEV-1:0] axi4_rready                   
);

localparam AEW = LOG2(DEW-1);

initial
begin
    axi4_awid =0;
    axi4_awaddr = 0;
    axi4_awlen = 0;
    axi4_awsize = 0;
    axi4_awburst = 0;
    axi4_awvalid = 0;

    axi4_wdata = 0;
    axi4_wstrb = 0;
    axi4_wlast = 0;
    axi4_wvalid = 0;

    axi4_arid = 0;
    axi4_araddr = 0;
    axi4_arlen = 0;
    axi4_arsize = 0;
    axi4_arburst = 0;
    axi4_arvalid = 0;
end

assign axi4_bready = {NDEV{1'b1}};
assign axi4_rready = {NDEV{1'b1}};

task axi4_write;
    input [3:0] dev;
    input [3:0] id;
    input [1:0] burst;
    input [31:0] addr;
    input [7:0] length;
    input [2:0] size;

    integer     pkgi ;

    reg [31:0] addr_temp;
begin   
    if(~rst_n)
        @(rst_n);
    @(posedge clk_axi[dev]);
    addr_temp <= addr;
    @(posedge clk_axi[dev]);
    axi4_awid[dev*IDW+:IDW] <= #U_DLY id;
    axi4_awaddr[dev*AW+:AW] <= #U_DLY addr_temp;
    axi4_awlen[dev*8+:8] <= #U_DLY length;
    axi4_awsize[dev*3+:3] <= #U_DLY size;
    axi4_awburst[dev*2+:2] <= #U_DLY burst;
    axi4_awvalid[dev] <= #U_DLY 1'b1;
    pkgi = 0;
    if(~(axi4_awvalid[dev] & axi4_awready[dev]))
        @(axi4_awvalid[dev] & axi4_awready[dev]);
    @(posedge clk_axi[dev]);
    axi4_awvalid[dev] <= #U_DLY 1'b0;

    while(pkgi <= length)
    begin
        axi4_wvalid[dev] <= #U_DLY 1;
        case(size)
            3'd0    : axi4_wdata[dev*DW+:DW] <= #U_DLY {DW{1'b0}} | (axi_wrmem[pkgi[7:0]*(2**0)*8+:(2**0)*8] << addr_temp[AEW-1:0]*8);
            3'd1    : axi4_wdata[dev*DW+:DW] <= #U_DLY {DW{1'b0}} | (axi_wrmem[pkgi[7:0]*(2**1)*8+:(2**1)*8] << addr_temp[AEW-1:0]*8);
            3'd2    : axi4_wdata[dev*DW+:DW] <= #U_DLY {DW{1'b0}} | (axi_wrmem[pkgi[7:0]*(2**2)*8+:(2**2)*8] << addr_temp[AEW-1:0]*8);
            3'd3    : axi4_wdata[dev*DW+:DW] <= #U_DLY {DW{1'b0}} | (axi_wrmem[pkgi[7:0]*(2**3)*8+:(2**3)*8] << addr_temp[AEW-1:0]*8);
            3'd4    : axi4_wdata[dev*DW+:DW] <= #U_DLY {DW{1'b0}} | (axi_wrmem[pkgi[7:0]*(2**4)*8+:(2**4)*8] << addr_temp[AEW-1:0]*8);
            3'd5    : axi4_wdata[dev*DW+:DW] <= #U_DLY {DW{1'b0}} | (axi_wrmem[pkgi[7:0]*(2**5)*8+:(2**5)*8] << addr_temp[AEW-1:0]*8);
            3'd6    : axi4_wdata[dev*DW+:DW] <= #U_DLY {DW{1'b0}} | (axi_wrmem[pkgi[7:0]*(2**6)*8+:(2**6)*8] << addr_temp[AEW-1:0]*8);
            3'd7    : axi4_wdata[dev*DW+:DW] <= #U_DLY {DW{1'b0}} | (axi_wrmem[pkgi[7:0]*(2**7)*8+:(2**7)*8] << addr_temp[AEW-1:0]*8);
            default : axi4_wdata[dev*DW+:DW] <= #U_DLY {DW{1'b0}} | (axi_wrmem[pkgi[7:0]*(2**0)*8+:(2**0)*8] << addr_temp[AEW-1:0]*8); 
        endcase

        case(size)
            3'd0    : axi4_wstrb[dev*DEW+:DEW] <= #U_DLY {DEW{1'b0}} | ({(2**0){1'b1}} <<addr_temp[AEW-1:0]);
            3'd1    : axi4_wstrb[dev*DEW+:DEW] <= #U_DLY {DEW{1'b0}} | ({(2**1){1'b1}} <<addr_temp[AEW-1:0]);
            3'd2    : axi4_wstrb[dev*DEW+:DEW] <= #U_DLY {DEW{1'b0}} | ({(2**2){1'b1}} <<addr_temp[AEW-1:0]);
            3'd3    : axi4_wstrb[dev*DEW+:DEW] <= #U_DLY {DEW{1'b0}} | ({(2**3){1'b1}} <<addr_temp[AEW-1:0]);
            3'd4    : axi4_wstrb[dev*DEW+:DEW] <= #U_DLY {DEW{1'b0}} | ({(2**4){1'b1}} <<addr_temp[AEW-1:0]);
            3'd5    : axi4_wstrb[dev*DEW+:DEW] <= #U_DLY {DEW{1'b0}} | ({(2**5){1'b1}} <<addr_temp[AEW-1:0]);
            3'd6    : axi4_wstrb[dev*DEW+:DEW] <= #U_DLY {DEW{1'b0}} | ({(2**6){1'b1}} <<addr_temp[AEW-1:0]);
            3'd7    : axi4_wstrb[dev*DEW+:DEW] <= #U_DLY {DEW{1'b0}} | ({(2**7){1'b1}} <<addr_temp[AEW-1:0]);
            default : axi4_wstrb[dev*DEW+:DEW] <= #U_DLY {DEW{1'b0}} | ({(2**0){1'b1}} <<addr_temp[AEW-1:0]);
        endcase     

        if(pkgi==length)
            axi4_wlast[dev] <= #U_DLY 1'b1;
        else
            axi4_wlast[dev] <= #U_DLY 1'b0;
        pkgi <= #U_DLY pkgi+1;
        
        if(burst > 'b0)
            addr_temp <= addr_temp + 2**size;

        @(posedge clk_axi[dev]);
        if(~(axi4_wvalid[dev]&axi4_wready[dev]))
        begin
            @(axi4_wvalid[dev] & axi4_wready[dev]);
            @(posedge clk_axi[dev]);
        end
    end
    axi4_wlast[dev] <= #U_DLY 1'b0;
    axi4_wstrb[dev*DEW+:DEW] <= #U_DLY 16'h0;
    axi4_wvalid[dev] <= #U_DLY 0;
    if(~(axi4_bvalid[dev] & axi4_bready[dev]))
        @(axi4_bvalid[dev] & axi4_bready[dev]);
end
endtask

task axi4_read;
    input [3:0] dev;
    input [3:0] id;
    input [1:0] burst;
    input [31:0] addr;
    input [7:0] length;
    input [2:0] size;
begin
    if(~rst_n)
        @(rst_n);
    @(posedge clk_axi[dev]);
    axi4_arid[dev*IDW+:IDW] <= #U_DLY id;
    axi4_araddr[dev*AW+:AW] <= #U_DLY addr;
    axi4_arlen[dev*8+:8] <= #U_DLY length;
    axi4_arsize[dev*3+:3] <= #U_DLY size;
    axi4_arburst[dev*2+:2] <= #U_DLY burst;
    axi4_arvalid[dev] <= #U_DLY 1'b1;

    if(~(axi4_arvalid[dev] & axi4_arready[dev]))
        @(axi4_arvalid[dev] & axi4_arready[dev]);

    @(posedge clk_axi[dev]);
    axi4_arvalid[dev] <= #U_DLY 1'b0;
    if(~(axi4_rvalid[dev] & axi4_rready[dev] & axi4_rlast[dev]))
        @(axi4_rvalid[dev] & axi4_rready[dev] & axi4_rlast[dev]);
end
endtask

function integer LOG2 ;
input integer d;
begin
    LOG2 = 1;
    while((2**LOG2-1) < d)
        LOG2 = LOG2 + 1;
end
endfunction


endmodule

